<link rel="import" href="../iron-collapse/iron-collapse.html">
<link rel="import" href="../iron-list/iron-list.html">
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../paper-icon-button/paper-icon-button.html">
<link rel="import" href="../paper-item/all-imports.html">
<link rel="import" href="../tf-graph-common/tf-graph-common.html">
<link rel="import" href="../tf-graph/tf-graph-icon.html">
<link rel="import" href="tf-node-list-item.html">

<dom-module id="tf-node-info">
  <style>
  .sub-list-group {
    padding: 8px 12px 0px;
    font-weight: 500;
    font-size: 12pt;
  }

  .sub-list {
    max-height: 300px;
    overflow-y: scroll;
  }

  .attr-left {
    float: left;
    width: 30%;
    word-wrap: break-word;
    color: #565656;
    font-size: 11pt;
    font-weight: 400;
  }

  .attr-right {
    margin-left: 30%;
    word-wrap: break-word;
    color: #565656;
    font-weight: 400;
  }

  paper-item {
    padding: 0;
    background: #e9e9e9;
  }

  paper-item-body[two-line] {
    min-height: 0;
    padding: 8px 12px 4px;
  }

  .expandedInfo {
    padding: 0 0 8px;
  }

  .controlDeps {
    padding: 0 0 0 8px;
  }

  .node-name {
    white-space: normal;
    word-wrap: break-word;
    font-size: 14pt;
    font-weight: 500;
  }

  .node-icon {
    float: right;
  }

  .subtitle {
    font-size: 12pt;
    color: #5e5e5e;
  }

  .controlLine {
    font-size: 11pt;
    font-weight: 400;
  }

  .toggle-button {
    float: right;
    max-height: 20px;
    max-width: 20px;
    padding: 0;
  }

  .control-toggle-button {
    float: left;
    max-height: 20px;
    max-width: 20px;
    padding: 0;
  }

  .toggle-include-group {
    padding-top: 4px;
  }

  .toggle-include {
    margin: 5px 6px;
    text-transform: none;
    padding: 4px 6px;
    font-size: 10pt;
    background-color: #fafafa;
    color: #666;
  }

  .toggle-include:hover {
    background-color: var(--google-yellow-100);
  }

  .non-control-list-item {
    padding-left: 10px;
  }
  </style>
  <template>
    <paper-item>
      <paper-item-body two-line>
        <div>
          <paper-icon-button
            icon="{{_getToggleIcon(_expanded)}}"
            on-click="_toggleExpanded"
            class="toggle-button">
          </paper-icon-button>
          <div class="node-name" id="nodetitle"></div>
        </div>
        <div secondary>
          <tf-graph-icon class="node-icon" node="[[_node]]"
              render-info="[[_getRenderInfo(nodeName, renderHierarchy)]]"
              color-by="[[colorBy]]"
              template-index="[[_templateIndex]]"
              ></tf-graph-icon>
          <template is="dom-if" if="{{_node.op}}">
            <div class="subtitle">
              Operation:
              <span>[[_node.op]]</span>
            </div>
          </template>
          <template is="dom-if" if="{{_node.metagraph}}">
            <div class="subtitle">
              Subgraph:
              <span>[[_node.cardinality]]</span> nodes
            </div>
          </template>
        </div>
      </paper-item-body>
    </paper-item>
    <iron-collapse opened="{{_expanded}}">
    <template is="dom-if" if="{{_expanded}}" restamp="true">
      <div class="expandedInfo">
        <div class="sub-list-group attributes">
          Attributes
          (<span>[[_attributes.length]]</span>)
          <iron-list class="sub-list" id ="attributesList"
                    items="[[_attributes]]">
            <template>
              <div>
                <div class="attr-left">[[item.key]]</div>
                <div class="attr-right">[[item.value]]</div>
              </div>
            </template>
          </iron-list>
        </div>

        <template is="dom-if" if="{{_device}}">
          <div class="sub-list-group device">
            <div class="attr-left">Device</div>
            <div class="attr-right">[[_device]]</div>
          </div>
        </template>

        <div class="sub-list-group predecessors">
          Inputs
          (<span>[[_totalPredecessors]]</span>)
          <iron-list class="sub-list" id ="inputsList"
                    items="[[_predecessors.regular]]">
            <template>
              <tf-node-list-item
                  class="non-control-list-item"
                  card-node="[[_node]]"
                  item-node="[[_getNode(item, graphHierarchy)]]"
                  edge-label="[[_getPredEdgeLabel(item)]]"
                  item-render-info="[[_getRenderInfo(item, renderHierarchy)]]"
                  name="[[item]]"
                  item-type="predecessors"
                  color-by="[[colorBy]]"
                  template-index="[[_templateIndex]]">
              </tf-node-list-item>
            </template>
          </iron-list>
          <template is="dom-if" if="[[_predecessors.control.length]]">
            <div class="controlDeps">
              <div class="controlLine">
                <paper-icon-button
                  icon="{{_getToggleIcon(_openedControlPred)}}"
                  on-click="_toggleControlPred"
                  class="control-toggle-button">
                </paper-icon-button>
                Control dependencies
              </div>
              <iron-collapse opened="{{_openedControlPred}}">
                <template is="dom-if" if="{{_openedControlPred}}" restamp="true">
                  <iron-list class="sub-list" items="[[_predecessors.control]]">
                    <template>
                      <tf-node-list-item
                          card-node="[[_node]]"
                          item-node="[[_getNode(item, graphHierarchy)]]"
                          item-render-info=
                              "[[_getRenderInfo(item, renderHierarchy)]]"
                          name="[[item]]"
                          item-type="predecessors"
                          color-by="[[colorBy]]"
                          template-index="[[_templateIndex]]">
                      </tf-node-list-item>
                    </template>
                  </iron-list>
                </template>
              </iron-collapse>
            </div>
          </template>
        </div>

        <div class="sub-list-group successors">
          Outputs
          (<span>[[_totalSuccessors]]</span>)
          <iron-list class="sub-list" id ="outputsList"
                    items="[[_successors.regular]]">
            <template>
              <tf-node-list-item
                  class="non-control-list-item"
                  card-node="[[_node]]"
                  item-node="[[_getNode(item, graphHierarchy)]]"
                  edge-label="[[_getSuccEdgeLabel(item)]]"
                  item-render-info="[[_getRenderInfo(item, renderHierarchy)]]"
                  name="[[item]]"
                  item-type="successor"
                  color-by="[[colorBy]]"
                  template-index="[[_templateIndex]]">
              </tf-node-list-item>
            </template>
          </iron-list>
          <template is="dom-if" if="[[_successors.control.length]]">
            <div class="controlDeps">
              <div class="controlLine">
                <paper-icon-button
                  icon="{{_getToggleIcon(_openedControlSucc)}}"
                  on-click="_toggleControlSucc"
                  class="control-toggle-button">
                </paper-icon-button>
                Control dependencies
              </div>
              <iron-collapse opened="{{_openedControlSucc}}">
                <template is="dom-if" if="{{_openedControlSucc}}" restamp="true">
                  <iron-list class="sub-list" items="[[_successors.control]]">
                    <template>
                      <tf-node-list-item
                          card-node="[[_node]]"
                          item-node="[[_getNode(item, graphHierarchy)]]"
                          item-render-info=
                              "[[_getRenderInfo(item, renderHierarchy)]]"
                          name="[[item]]"
                          item-type="successors"
                          color-by="[[colorBy]]"
                          template-index="[[_templateIndex]]">
                      </tf-node-list-item>
                    </template>
                  </iron-list>
                </template>
              </iron-collapse>
            </div>
          </template>
        </div>
        <div class="toggle-include-group">
          <paper-button raised class="toggle-include" on-click="_toggleInclude">
            <span>[[_auxButtonText]]</span>
          </paper-button>
        </div>
        <template is="dom-if" if="{{_isInSeries(_node)}}">
          <div class="toggle-include-group">
            <paper-button raised class="toggle-include" on-click="_toggleGroup">
              <span>[[_groupButtonText]]</span>
            </paper-button>
          </div>
        </template>
      </div>
    </template>
    </iron-collapse>
  </template>

  <script>
    (function() {
      Polymer({
        is: 'tf-node-info',

        properties: {
          nodeName: String,
          graphHierarchy: Object,
          renderHierarchy: Object,
          /** What to color the nodes by (compute time, memory, device etc.) */
          colorBy: String,
          _templateIndex: {
            type: Function,
            computed: '_getTemplateIndex(graphHierarchy)'
          },
          _node: {
            type: Object,
            computed: '_getNode(nodeName, graphHierarchy)',
            observer: '_resetState'
          },
          // The enum value of the include property of the selected node.
          nodeInclude: {
            type: Number,
            observer: '_nodeIncludeStateChanged'
          },
          _attributes: {
            type: Array,
            computed: '_getAttributes(_node)'
          },
          _device: {
            type: String,
            computed: '_getDevice(_node)'
          },
          _successors: {
            type: Object,
            computed: '_getSuccessors(_node, graphHierarchy)'
          },
          _predecessors: {
            type: Object,
            computed: '_getPredecessors(_node, graphHierarchy)'
          },
          _subnodes: {
            type: Array,
            computed: '_getSubnodes(_node)'
          },
          _expanded: {
            type: Boolean,
            value: true
          },
          _totalPredecessors: {
            type: Number,
            computed: '_getTotalPred(_predecessors)'
          },
          _totalSuccessors: {
            type: Number,
            computed: '_getTotalSucc(_successors)'
          },
          _openedControlPred: {
            type: Boolean,
            value: false
          },
          _openedControlSucc: {
            type: Boolean,
            value: false
          },
          _auxButtonText: String,
          _groupButtonText: String
        },
        expandNode: function() {
          this.fire('_node.expand', this.node);
        },
        _getTemplateIndex: function(graphHierarchy) {
          return graphHierarchy.getTemplateIndex();
        },
        _getNode: function(nodeName, graphHierarchy) {
          return graphHierarchy.node(nodeName);
        },
        _getPrintableHTMLNodeName: function(nodeName) {
          // Insert an optional line break before each slash so that
          // long node names wrap cleanly at path boundaries.
          return (nodeName || '').replace(/\//g, '<wbr>/');
        },
        _getPredEdgeLabel: function(sourceName) {
          return this._getEdgeLabel(sourceName, this.nodeName);
        },
        _getSuccEdgeLabel: function(destName) {
          return this._getEdgeLabel(this.nodeName, destName);
        },
        _getEdgeLabel: function(sourceName, destName) {
          if (!this._node) {
            // The user clicked outside, thus no node is selected and
            // the info card should be hidden.
            return;
          }
          var parent = this._node.parentNode;
          var sourceNode = this.graphHierarchy.node(sourceName);
          if (!sourceNode.isGroupNode) {
            // Show the tensor shape directly.
            return tf.graph.scene.edge.getShapeLabelFromNode(sourceNode);
          }
          sourceName = this.renderHierarchy.getNearestVisibleAncestor(sourceName);
          destName = this.renderHierarchy.getNearestVisibleAncestor(destName);
          var metaedge = parent.metagraph.edge(sourceName, destName) ||
              parent.bridgegraph.edge(sourceName, destName);
          return tf.graph.scene.edge.getLabelForEdge(metaedge,
              this.renderHierarchy);
        },
        _getRenderInfo: function(nodeName, renderHierarchy) {
          return this.renderHierarchy.getOrCreateRenderNodeByName(nodeName);
        },
        _getAttributes: function(node) {
          this.async(this._resizeList.bind(this, "#attributesList"));
          return node && node.attr ? node.attr.map(function(entry) {
            return {key: entry.key, value: JSON.stringify(entry.value)};
          }) : [];

        },
        _getDevice: function(node) {
          return node ? node.device : null;
        },
        _getSuccessors: function(node, hierarchy) {
          this.async(this._resizeList.bind(this, "#inputsList"));
          return node ? hierarchy.getSuccessors(node.name) : [[], []];
        },
        _getPredecessors: function(node, hierarchy) {
          this.async(this._resizeList.bind(this, "#outputsList"));
          return node ? hierarchy.getPredecessors(node.name) : [[], []];
        },
        _getSubnodes: function(node) {
          return node && node.metagraph ? node.metagraph.nodes() : null;
        },
        _getTotalPred: function(predecessors) {
          return predecessors.regular.length + predecessors.control.length;
        },
        _getTotalSucc: function(successors) {
          return successors.regular.length + successors.control.length;
        },
        _toggleControlPred: function() {
          this._openedControlPred = !this._openedControlPred;
        },
        _toggleControlSucc: function() {
          this._openedControlSucc = !this._openedControlSucc;
        },
        _toggleExpanded: function() {
          this._expanded = !this._expanded;
        },
        _getToggleIcon: function(expanded) {
          return expanded ? "expand-less" : "expand-more";
        },
        _resetState: function() {
          this._openedControlPred = false;
          this._openedControlSucc = false;

          this.set("_groupButtonText",
            tf.graph.scene.node.getGroupSettingLabel(this._node));

          if (this._node) {
            Polymer.dom(this.$.nodetitle).innerHTML =
              this._getPrintableHTMLNodeName(this._node.name);
          }
        },
        _resizeList: function(selector) {
          var list = document.querySelector(selector);
          if (list) {
            list.fire('iron-resize');
          }
        },
        _toggleInclude: function() {
          var graphElem = document.querySelector("#graph");
          graphElem.fire("node-toggle-extract", { name: this.nodeName });
          var graphBoardElem = document.querySelector("#graphboard");
          graphBoardElem.fire("node-toggle-extract");
        },
        _nodeIncludeStateChanged: function(include, oldInclude) {
          this.set("_auxButtonText",
            tf.graph.getIncludeNodeButtonString(include));
        },
        _toggleGroup: function() {
          var graphElem = document.querySelector("#graph");
          var seriesName = tf.graph.scene.node.getSeriesName(this._node);
          graphElem.fire("node-toggle-seriesgroup", { name: seriesName });
        },
        _isInSeries: function(node) {
          return tf.graph.scene.node.canBeInSeries(node);
        }
      });
    })();
  </script>
</dom-module>
